import { _decorator, Component, Node, EventTouch, UITransform, Vec3, v3, Touch, Vec2, EventMouse, Tween, tween, easing, CCFloat, CCBoolean, log, v2, clamp } from 'cc';
const { ccclass, property } = _decorator;

/**视图组件 */
@ccclass('ZoomViewport')
export class ZoomViewport extends Component {

    @property(Node)
    maskNode: Node = null;

    @property(Node)
    contentNode: Node = null;

    @property(CCFloat)
    maxScale: number = 2;

    @property(CCFloat)
    minScale: number = 1;

    @property(CCFloat)
    scaleUtil: number = 0.05;
    /**缓动 */
    @property(CCBoolean)
    inertia: boolean = false;

    @property(CCBoolean)
    canDrag: boolean = true;

    @property(CCBoolean)
    cancelInnerEventOnMove: boolean = true;

    protected startPos1: Vec3;

    protected startPos2: Vec3;

    /**点击中的两点的距离 */
    protected prePointsDis: number = 0;

    protected _touchMoved = false

    protected scaleChangedInThisOperation = false

    protected firstMovePos: Vec3 = null

    protected firstMoveTime: number = 0


    touchingCount = 0

    protected moveTween: Tween<any> = null


    get width() {
        return this.contentNode.getComponent(UITransform).width
    }

    get height() {
        return this.contentNode.getComponent(UITransform).height
    }

    setContentScale(scale: number) {
        this.stopMoveTween()
        const oldScale = this.contentNode.scale.x;
        this.contentNode.setPosition(
            this.contentNode.position.x * (scale / oldScale),
            this.contentNode.position.y * (scale / oldScale),
        )


        this.contentNode.setScale(scale, scale, 1);
    }

    protected onLoad() {




        this.node.on(Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

    }
    get contentNodeScale() {
        return this.contentNode.scale.x
    }



    protected onEnable(): void {
        if (!this.contentNode && this.maskNode && this.maskNode.children[0]) {
            this.contentNode = this.maskNode.children[0]
        }


        this.scheduleOnce(
            () => {
                this.resetRictContent()
            }
        )
    }

    protected onDestroy(): void {
        this.stopMoveTween()
        this.unscheduleAllCallbacks()
    }

    protected onMouseWheel(event: EventMouse) {
        let distance = event.getScrollY();
        if (distance >= 0) {
            if (this.contentNodeScale >= this.maxScale) {
                this.setContentScale(this.maxScale)
                this.resetRictContent()
                return
            }
            this.setContentScale(this.contentNodeScale + this.scaleUtil)
            this.resetRictContent()
        } else {
            if (this.contentNodeScale - this.scaleUtil <= this.minScale) {
                this.setContentScale(this.minScale)
                this.resetRictContent()
                return
            }
            this.setContentScale(this.contentNodeScale - this.scaleUtil)
            this.resetRictContent()
        }
    }


    protected onTouchStart(event: EventTouch) {
        if (event.target !== this.node) {
            event.preventSwallow = true

            return
        }
        this.stopMoveTween()

        this.touchingCount++

        const touches = event.getTouches()
        // console.log("on zoomView TouchStart :", touches.length, this.touchingCount);

        if (this.touchingCount == 1) {
            this._touchMoved = false;

            this.scaleChangedInThisOperation = false
            this.firstMovePos = null
            this.firstMoveTime = 0
            this.preTouchMovePos = null
            this.prePointsDis = 0
        }

        this._stopPropagationIfTargetIsMe(event);
    }

    v2ToV3(v2: Vec2, out: Vec3 = v3()) {
        return out.set(v2.x, v2.y)
    }

    /**上次拖拽位置 */
    preTouchMovePos: Vec3 = null

    /**用来移动的临时变量 */
    private _tempV3ForMove: Vec3 = v3()

    onTouchMove(event: EventTouch) {

        const touches = event.getTouches()
        // console.log("on zoomView TouchMove :", touches.length, this.touchingCount);
        if (this.touchingCount == 1) {
            if (!this.canDrag) return
            const uit = this.maskNode.getComponent(UITransform)

            let deltaMoveFromStart = event.touch.getUILocation().subtract(event.touch.getUIStartLocation())
            const pos = uit.convertToNodeSpaceAR(this.v2ToV3(touches[0].getUILocation()))
            this._tempV3ForMove.set(pos)
            const delta = this.preTouchMovePos ? this._tempV3ForMove.subtract(this.preTouchMovePos) : this._tempV3ForMove.set(0, 0, 0)
            this.contentNode.setPosition(this.contentNode.position.add(delta))
            this.resetRictContent()

            if (!this.firstMovePos) {
                this.firstMovePos = pos
                this.firstMoveTime = Date.now()
            }
            this.preTouchMovePos = pos.clone()

            /**中断容器内其他节点的点击事件 */
            if (this.cancelInnerEventOnMove && deltaMoveFromStart.length() > 7) {

                this.stopMoveTween()
                if (!this._touchMoved && event.target !== this.node) {
                    let cancelEvent = new EventTouch(event.getTouches(), event.bubbles, Node.EventType.TOUCH_CANCEL);
                    cancelEvent.touch = event.touch;

                    (cancelEvent as any).simulate = true;
                    event.target.dispatchEvent(cancelEvent);
                    this._touchMoved = true
                }
            }

        } else if (this.touchingCount == 2 && touches.length == 2) {
            const uit = this.node.getComponent(UITransform)
            const touchPoint1 = touches[0].getUILocation()
            const touchPoint2 = touches[1].getUILocation()

            const newPointDis = Vec2.distance(touchPoint1, touchPoint2)

            if (Math.abs(newPointDis - this.prePointsDis) < 5) return

            if (!this.prePointsDis) {
                this.prePointsDis = newPointDis
            }

            if (newPointDis > this.prePointsDis) {
                if (this.contentNodeScale + this.scaleUtil >= this.maxScale) {

                    if (this.contentNodeScale != this.maxScale) {
                        this.setContentScale(this.maxScale)
                    }
                    this.prePointsDis = newPointDis

                    return
                }

                this.prePointsDis = newPointDis
                this.setContentScale(this.contentNodeScale + this.scaleUtil)
                this.scaleChangedInThisOperation = true

            } else if (newPointDis < this.prePointsDis) {

                if (this.contentNodeScale - this.scaleUtil <= this.minScale) {

                    if (this.contentNodeScale != this.minScale) {
                        this.setContentScale(this.minScale)
                    }
                    this.prePointsDis = newPointDis

                    return
                }

                this.prePointsDis = newPointDis
                this.setContentScale(this.contentNodeScale - this.scaleUtil)
                this.scaleChangedInThisOperation = true
            }


            this.resetRictContent()

        }

        this._stopPropagationIfTargetIsMe(event);
    }


    onTouchEnd(event: EventTouch) {

        if (event.target !== this.node) {
            event.preventSwallow = true

            return
        }
        const touches: Touch[] = event.getTouches()


        this.touchingCount--
        // console.log("on zoomView TouchEnd :", touches.length, this.touchingCount);

        // let deltaMoveFromStart = event.touch.getUILocation().subtract(event.touch.getStartLocation())

        // const gp = this.contentNode.getComponent(UITransform).convertToNodeSpaceAR(this.v2ToV3(event.getUILocation()))
        if (this._touchMoved) {
            event.preventSwallow = false
        } else {
            this._stopPropagationIfTargetIsMe(event);
        }
        this._stopPropagationIfTargetIsMe(event);


        if (this.inertia && !this.scaleChangedInThisOperation && this.firstMovePos && touches.length == 1) {
            const uit = this.maskNode.getComponent(UITransform)

            if (!this.firstMoveTime || Date.now() - this.firstMoveTime > 200) {
                return
            }

            const touchEndLocation = uit.convertToNodeSpaceAR(this.v2ToV3(touches[0].getUILocation()))
            const dist = Vec2.distance(touchEndLocation, this.firstMovePos)

            const targetPos = (this.contentNode.position.clone().add(touchEndLocation.clone().subtract(this.firstMovePos).multiplyScalar(clamp(dist / 200, 0.7, 1.5))))
            this.resetRictContent(targetPos)
            // if (dist < 200) {
            //     return
            // }
            this.startMoveCamaraTween(targetPos, Math.min(Date.now() - this.firstMoveTime / 1000, 1))

        }
    }

    stopMoveTween() {
        if (this.moveTween) {
            this.moveTween.stop()
            this.moveTween = null
        }
    }

    startMoveCamaraTween(targetPos: Vec3, duration: number, easing = 'quintOut') {
        // console.log("startMoveCamaraTween", targetPos, duration, "");
        this.resetRictContent(targetPos)
        this.stopMoveTween()
        this.moveTween = tween(this.contentNode).to(duration, { position: targetPos },
            { easing: "quintOut" },

        ).call(() => {
            this.contentNode.setPosition(targetPos)
            this.moveTween = null
        }).start()
    }

    protected _stopPropagationIfTargetIsMe(event: EventTouch) {
        if (event.eventPhase === Event.AT_TARGET && event.target === this.node) {
            event.preventSwallow = false
        }
    }

    /**
     * 视图相机当前位置
     * @param out 
     * @returns 
     */
    getCamaraPos(out: Vec3 = v3()) {
        let viewCamaraPos = this.contentNode.position
        return out.set(viewCamaraPos.x / this.contentNodeScale * -1, viewCamaraPos.y / this.contentNodeScale * -1, 0)
    }

    /**
     * 移动视图相机到指定位置
     * @param pos 
     * @param duration 
     * @param resetRectContent 
     * @param force 
     * @param easing 
     * @returns 
     */
    moveCameraTo(pos: Vec3, duration = 0, resetRectContent: boolean = true, force = true, easing = 'quintOut') {

        if (!force && this.moveTween) {
            return
        }

        const targetPos = this._tempV3ForMove.set(pos.x * this.contentNodeScale * -1, pos.y * this.contentNodeScale * -1, 0)
        resetRectContent && this.resetRictContent()
        if (duration) {
            this.startMoveCamaraTween(targetPos, duration, easing)
        } else {
            this.contentNode.setPosition(targetPos)
        }
    }

    private _tempV3ForResetRictContent = v3()

    resetRictContent(targetNodeOrVec: any = this.contentNode) {
        const contentWidth = this.contentNode.getComponent(UITransform).getBoundingBox().width
        const contentHeight = this.contentNode.getComponent(UITransform).getBoundingBox().height


        const targetPos = targetNodeOrVec.position ? this._tempV3ForResetRictContent.set(targetNodeOrVec.position.x, targetNodeOrVec.position.y, targetNodeOrVec.position.z) : targetNodeOrVec

        const maskUit = this.maskNode.getComponent(UITransform)

        if (targetPos.x > 0 && targetPos.x - 0 > contentWidth / 2 - maskUit.width / 2) {
            targetPos.x = contentWidth / 2 - maskUit.width / 2
        }

        if (targetPos.x < 0 && targetPos.x - 0 < maskUit.width / 2 - contentWidth / 2) {
            targetPos.x = maskUit.width / 2 - contentWidth / 2
        }

        if (targetPos.y > 0 && targetPos.y - 0 > contentHeight / 2 - maskUit.height / 2) {
            targetPos.y = contentHeight / 2 - maskUit.height / 2
        }

        if (targetPos.y < 0 && targetPos.y - 0 < maskUit.height / 2 - contentHeight / 2) {
            targetPos.y = maskUit.height / 2 - contentHeight / 2
        }

        targetNodeOrVec.position && targetNodeOrVec.setPosition(targetPos)
    }
}